home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / gnu / bash / bash_108 / bash-108.zoo / src / trap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-12  |  11.8 KB  |  483 lines

  1. /* trap.c -- Not the trap command, but useful functions
  2.    for manipulating those objects.  The trap command is
  3.    in builtins.c */
  4.  
  5. /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
  6.  
  7. This file is part of GNU Bash, the Bourne Again SHell.
  8.  
  9. Bash is free software; you can redistribute it and/or modify it under
  10. the terms of the GNU General Public License as published by the Free
  11. Software Foundation; either version 1, or (at your option) any later
  12. version.
  13.  
  14. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  15. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17. for more details.
  18.  
  19. You should have received a copy of the GNU General Public License along
  20. with Bash; see the file COPYING.  If not, write to the Free Software
  21. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. #include "trap.h"
  24. #include "shell.h"
  25.  
  26. /* The list of things to do originally, before we started trapping. */
  27. SigHandler *original_signals[NSIG];
  28.  
  29. /* For each signal, a slot for a string, which is a command to be
  30.    executed when that signal is recieved.  The slot can also contain
  31.    DEFAULT_SIG, which means do whatever you were going to do before
  32.    you were so rudely interrupted, or IGNORE_SIG, which says ignore
  33.    this signal. */
  34. char *trap_list[NSIG];
  35.  
  36. /* A translation list so we can be polite to our users. */
  37. char *signal_names[NSIG];
  38.  
  39. /* A bitmap of signals received for which we have trap handlers. */
  40. int pending_traps[NSIG];
  41.  
  42. static int signal_names_initialized = 0;
  43.  
  44.  
  45. initialize_traps ()
  46. {
  47.   register int i;
  48.  
  49.   if (!signal_names_initialized)
  50.     {
  51.       for (i = 1; i < NSIG; i++)
  52.         {
  53.       signal_names[i] = (char *)NULL;
  54.       pending_traps[i] = 0;
  55.         }
  56.  
  57.       /* `signal' 0 is what we do on exit. */
  58.       signal_names[0] = "EXIT";
  59.  
  60. #if defined (SIGHUP)        /* hangup */
  61.       signal_names[SIGHUP] = "SIGHUP";
  62. #endif
  63.  
  64. #if defined (SIGINT)        /* interrupt */
  65.       signal_names[SIGINT] = "SIGINT";
  66. #endif
  67.  
  68. #if defined (SIGQUIT)        /* quit */
  69.       signal_names[SIGQUIT] = "SIGQUIT";
  70. #endif
  71.  
  72. #if defined (SIGILL)        /* illegal instruction (not reset when caught) */
  73.       signal_names[SIGILL] = "SIGILL";
  74. #endif
  75.  
  76. #if defined (SIGTRAP)        /* trace trap (not reset when caught) */
  77.       signal_names[SIGTRAP] = "SIGTRAP";
  78. #endif
  79.  
  80. #if defined (SIGABRT)        /*  */
  81.       signal_names[SIGABRT] = "SIGABRT";
  82. #endif
  83.  
  84. #if defined (SIGIOT)        /* IOT instruction */
  85.       signal_names[SIGIOT] = "SIGIOT";
  86. #endif
  87.  
  88. #if defined (SIGEMT)        /* EMT instruction */
  89.       signal_names[SIGEMT] = "SIGEMT";
  90. #endif
  91.  
  92. #if defined (SIGFPE)        /* floating point exception */
  93.       signal_names[SIGFPE] = "SIGFPE";
  94. #endif
  95.  
  96. #if defined (SIGKILL)        /* kill (cannot be caught or ignored) */
  97.       signal_names[SIGKILL] = "SIGKILL";
  98. #endif
  99.  
  100. #if defined (SIGBUS)        /* bus error */
  101.       signal_names[SIGBUS] = "SIGBUS";
  102. #endif
  103.  
  104. #if defined (SIGSEGV)        /* segmentation violation */
  105.       signal_names[SIGSEGV] = "SIGSEGV";
  106. #endif
  107.  
  108. #if defined (SIGSYS)        /* bad argument to system call */
  109.       signal_names[SIGSYS] = "SIGSYS";
  110. #endif
  111.  
  112. #if defined (SIGPIPE)        /* write on a pipe with no one to read it */
  113.       signal_names[SIGPIPE] = "SIGPIPE";
  114. #endif
  115.  
  116. #if defined (SIGALRM)        /* alarm clock */
  117.       signal_names[SIGALRM] = "SIGALRM";
  118. #endif
  119.  
  120. #if defined (SIGTERM)        /* software termination signal from kill */
  121.       signal_names[SIGTERM] = "SIGTERM";
  122. #endif
  123.  
  124. #if defined (SIGCLD)        /* Like SIGCHLD.  */
  125.       signal_names[SIGCLD] = "SIGCLD";
  126. #endif
  127.  
  128. #if defined (SIGPWR)        /* Magic thing for some machines. */
  129.       signal_names[SIGPWR] = "SIGPWR";
  130. #endif
  131.  
  132. #if defined (SIGPOLL)        /* For keyboard input?  */
  133.       signal_names[SIGPOLL] = "SIGPOLL";
  134. #endif
  135.  
  136. #if defined (SIGURG)        /* urgent condition on IO channel */
  137.       signal_names[SIGURG] = "SIGURG";
  138. #endif
  139.  
  140. #if defined (SIGSTOP)        /* sendable stop signal not from tty */
  141.       signal_names[SIGSTOP] = "SIGSTOP";
  142. #endif
  143.  
  144. #if defined (SIGTSTP)        /* stop signal from tty */
  145.       signal_names[SIGTSTP] = "SIGTSTP";
  146. #endif
  147.  
  148. #if defined (SIGCONT)        /* continue a stopped process */
  149.       signal_names[SIGCONT] = "SIGCONT";
  150. #endif
  151.  
  152. #if defined (SIGCHLD)        /* to parent on child stop or exit */
  153.       signal_names[SIGCHLD] = "SIGCHLD";
  154. #endif
  155.  
  156. #if defined (SIGTTIN)        /* to readers pgrp upon background tty read */
  157.       signal_names[SIGTTIN] = "SIGTTIN";
  158. #endif
  159.  
  160. #if defined (SIGTTOU)        /* like TTIN for output if (tp->t_local<OSTOP) */
  161.       signal_names[SIGTTOU] = "SIGTTOU";
  162. #endif
  163.  
  164. #if defined (SIGIO)        /* input/output possible signal */
  165.       signal_names[SIGIO] = "SIGIO";
  166. #endif
  167.  
  168. #if defined (SIGXCPU)        /* exceeded CPU time limit */
  169.       signal_names[SIGXCPU] = "SIGXCPU";
  170. #endif
  171.  
  172. #if defined (SIGXFSZ)        /* exceeded file size limit */
  173.       signal_names[SIGXFSZ] = "SIGXFSZ";
  174. #endif
  175.  
  176. #if defined (SIGVTALRM)        /* virtual time alarm */
  177.       signal_names[SIGVTALRM] = "SIGVTALRM";
  178. #endif
  179.  
  180. #if defined (SIGPROF)        /* profiling time alarm */
  181.       signal_names[SIGPROF] = "SIGPROF";
  182. #endif
  183.  
  184. #if defined (SIGWINCH)        /* window changed */
  185.       signal_names[SIGWINCH] = "SIGWINCH";
  186. #endif
  187.  
  188. #if defined (SIGLOST)        /* resource lost (eg, record-lock lost) */
  189.       signal_names[SIGLOST] = "SIGLOST";
  190. #endif
  191.  
  192. #if defined (SIGUSR1)        /* user defined signal 1 */
  193.       signal_names[SIGUSR1] = "SIGUSR1";
  194. #endif
  195.  
  196. #if defined (SIGUSR2)        /* user defined signal 2 */
  197.       signal_names[SIGUSR2] = "SIGUSR2";
  198. #endif
  199.  
  200. #if defined (SIGMSG)    /* HFT input data pending */
  201.       signal_names[SIGMSG] = "SIGMSG";
  202. #endif
  203.  
  204. #if defined (SIGPWR)    /* power failure imminent (save your data) */
  205.       signal_names[SIGPWR] = "SIGPWR";
  206. #endif
  207.  
  208. #if defined (SIGDANGER)    /* system crash imminent */
  209.       signal_names[SIGDANGER] = "SIGDANGER";
  210. #endif
  211.  
  212. #if defined (SIGMIGRATE)    /* migrate process to another CPU */
  213.       signal_names[SIGMIGRATE] = "SIGMIGRATE";
  214. #endif
  215.  
  216. #if defined (SIGPRE)    /* programming error */
  217.       signal_names[SIGPRE] = "SIGPRE";
  218. #endif
  219.  
  220. #if defined (SIGGRANT)    /* HFT monitor mode granted */
  221.       signal_names[SIGGRANT] = "SIGGRANT";
  222. #endif
  223.  
  224. #if defined (SIGRETRACT)    /* HFT monitor mode retracted */
  225.       signal_names[SIGRETRACT] = "SIGRETRACT";
  226. #endif
  227.  
  228. #if defined (SIGSOUND)    /* HFT sound sequence has completed */
  229.       signal_names[SIGSOUND] = "SIGSOUND";
  230. #endif
  231.  
  232.       for (i = 0; i < NSIG; i++)
  233.     if (signal_names[i] == (char *)NULL)
  234.       {
  235.         signal_names[i] = (char *)xmalloc (10 + strlen ("SIGJUNK"));
  236.         sprintf (signal_names[i], "SIGJUNK(%d)", i);
  237.       }
  238.     }
  239.  
  240.  
  241.   trap_list[0] = (char *)NULL;
  242.  
  243.   for (i = 1; i < NSIG; i++)
  244.     {
  245.       trap_list[i] = (char *)DEFAULT_SIG;
  246.       original_signals[i] = (SigHandler *)signal (i, SIG_DFL);
  247.       signal (i, original_signals[i]);
  248.     }
  249. }
  250.  
  251. /* Return the print name of this signal. */
  252. char *
  253. signal_name (signal)
  254.      int signal;
  255. {
  256.   if (signal > NSIG)
  257.      return ("bad signal number");
  258.   else return (signal_names[signal]);
  259. }
  260.  
  261. /* Turn a string into a signal number, or a number into
  262.    a signal number.  If STRING was "2", "SIGINT", or "INT",
  263.    then (int)2 would be returned. */
  264. int
  265. decode_signal (string)
  266.      char *string;
  267. {
  268.   int sig;
  269.  
  270.   if (sscanf (string, "%d", &sig) == 1) {
  271.     if (sig < NSIG && sig >= 0)
  272.       return (sig);
  273.     else
  274.       return (NO_SIG);
  275.   }
  276.       
  277.   for (sig = 0; sig < NSIG; sig++)
  278.      if ((stricmp (string, signal_names[sig]) == 0) ||
  279.      (stricmp (string, &(signal_names[sig])[3]) == 0))
  280.        return (sig);
  281.  
  282.   return (NO_SIG);
  283. }
  284.  
  285. /* Non-zero when we catch a trapped signal. */
  286. static int catch_flag = 0;
  287.  
  288. /**
  289.  ** (sjk)++ NO BSD type signals on the Atari ST1
  290.  **/
  291. #if !defined(atarist)
  292. #if !defined (USG) && !defined (USGr4)
  293. #define HAVE_BSD_SIGNALS
  294. #endif
  295. #endif
  296.  
  297. run_pending_traps ()
  298. {
  299.   register int sig;
  300.   extern int last_command_exit_value;
  301.   int old_exit_value;
  302.  
  303.   if (catch_flag == 0)        /* simple optimization */
  304.     return;
  305.  
  306.   catch_flag = 0;
  307.  
  308.   /* Preserve $? when running trap. */
  309.   old_exit_value = last_command_exit_value;
  310.  
  311.   for (sig = 0; sig < NSIG; sig++)
  312.     {
  313.       if (pending_traps[sig])
  314.     {
  315. #if defined (_POSIX_VERSION)
  316.       sigset_t set, oset;
  317.       sigemptyset (&set);
  318.       sigaddset (&set, sig);
  319.       sigprocmask (SIG_BLOCK, &set, &oset);
  320. #else
  321. #  if defined (HAVE_BSD_SIGNALS)
  322.       int oldmask = sigblock (sigmask (sig));
  323. #  endif
  324. #endif /* POSIX_VERSION */
  325.  
  326.       parse_and_execute (savestring (trap_list[sig]), "trap");
  327.       pending_traps[sig] = 0;
  328.  
  329. #if defined (_POSIX_VERSION)
  330.       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  331. #else
  332. #  if defined (HAVE_BSD_SIGNALS)
  333.       sigsetmask (oldmask);
  334. #  endif
  335. #endif /* POSIX_VERSION */
  336.     }
  337.     }
  338.  
  339.   last_command_exit_value = old_exit_value;
  340. }
  341.  
  342. sighandler
  343. trap_handler (sig)
  344.      int sig;
  345. {
  346.   if ((sig >= NSIG) ||
  347.       (trap_list[sig] == (char *)DEFAULT_SIG) ||
  348.       (trap_list[sig] == (char *)IGNORE_SIG))
  349.     programming_error ("trap_handler: Bad signal %d", sig);
  350.   else
  351.     {
  352.       catch_flag = 1;
  353.       pending_traps[sig]++;
  354.     }
  355. }
  356.  
  357. /* Set SIG to call STRING as a command. */
  358. void
  359. set_signal (sig, string)
  360.      int sig;
  361.      char *string;
  362. {
  363.   void change_signal ();
  364.  
  365.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  366.      no error is reported when attempting to do so.  -- Posix.2 */
  367.   if (original_signals[sig] == SIG_IGN)
  368.     return;
  369.  
  370. #if  defined(SIGCHLD)
  371.   /* Don't change the function that catches SIGCHLD, but store the command
  372.      to be executed.  It will be run from jobs.c: flush_child(). */
  373.   if (sig && (sig != SIGCHLD))
  374. #else
  375.   if (sig)
  376. #endif
  377.     signal (sig, SIG_IGN);
  378.  
  379.   change_signal (sig, savestring (string));
  380.  
  381. #if defined(SIGCHLD)
  382.   /* Don't change the function that catches SIGCHLD, but store the command
  383.      to be executed.  It will be run from jobs.c: flush_child(). */
  384.   if (sig && (sig != SIGCHLD))
  385. #else
  386.   if (sig)
  387. #endif
  388.     signal (sig, trap_handler);
  389. }
  390.  
  391. /* If SIG has a string assigned to it, get rid of it.  Then give it
  392.    VALUE. */
  393. void
  394. change_signal (sig, value)
  395.      int sig;
  396.      char *value;
  397. {
  398.   if ((((int)trap_list[sig]) > 0) && (trap_list[sig] != (char *)IGNORE_SIG))
  399.     free (trap_list[sig]);
  400.   trap_list[sig] = value;
  401. }
  402.  
  403. /* Restore the default action for SIG; i.e., the action the shell
  404.    would have taken before you used the trap command. */
  405. void
  406. restore_default_signal (sig)
  407.      int sig;
  408. {
  409.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  410.   if (sig != SIGCHLD)
  411.     signal (sig, original_signals[sig]);
  412.   change_signal (sig, (char *)DEFAULT_SIG);
  413. }
  414.  
  415. /* Make this signal be ignored. */
  416. void
  417. ignore_signal (sig)
  418.      int sig;
  419. {
  420.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  421.   if (sig != SIGCHLD)
  422.     signal (sig, SIG_IGN);
  423.   change_signal (sig, (char *)IGNORE_SIG);
  424. }
  425.  
  426. /* Handle the calling of "trap 0".  The only sticky situation is when
  427.    the command to be executed includes an "exit".  This is why we have
  428.    to provide our own place for top_level to jump to. */
  429. void
  430. run_exit_trap ()
  431. {
  432.   if ((trap_list[0] != (char *)DEFAULT_SIG) &&
  433.       (trap_list[0] != (char *)IGNORE_SIG))
  434.     {
  435.       char *trap_command = savestring (trap_list[0]);
  436.       int code;
  437.  
  438.       change_signal (0, (char *)NULL);
  439.       code = setjmp (top_level);
  440.       if (code == 0)
  441.     parse_and_execute (trap_command, "trap");
  442.     }
  443. }
  444.       
  445. /* Reset all trapped signals to their original values.  Signals set to be
  446.    ignored with trap '' SIGNAL should be ignored, so we make sure that they
  447.    are. */
  448. void
  449. restore_original_signals ()
  450. {
  451.   register int i;
  452.  
  453.   for (i = 0; i < NSIG; i++)
  454.     {
  455.       if (trap_list[i] != (char *)DEFAULT_SIG)
  456.     {
  457.       if (trap_list[i] == (char *)IGNORE_SIG)
  458.         signal (i, SIG_IGN);
  459.       else
  460.         restore_default_signal (i);
  461.     }
  462.     }
  463. }
  464.  
  465. /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
  466.    declared here to localize the trap functions. */
  467. run_interrupt_trap ()
  468. {
  469.   char *command;
  470.   int old_exit_value;
  471.   extern int last_command_exit_value;
  472.  
  473.   if ((trap_list[SIGINT] != (char *) DEFAULT_SIG) &&
  474.       (trap_list[SIGINT] != (char *) IGNORE_SIG))
  475.     {
  476.       command = savestring (trap_list[SIGINT]);
  477.  
  478.       old_exit_value = last_command_exit_value;
  479.       parse_and_execute (command, "interrupt trap");
  480.       last_command_exit_value = old_exit_value;
  481.     }
  482. }
  483.